name: Schedule

on:
 schedule:
 - cron: 0 4 * * *
 push:
  paths:
  - '.github/workflows/schedule.yml'
  - '.github/workflows/scripts/compile-ssl.sh'
  - '.github/workflows/scripts/ddraw.sh'
  - '.github/workflows/scripts/ddraw.merge.awk'
  - '.github/workflows/scripts/format-msg.sh'
  - '.github/workflows/scripts/format-ssl.sh'
  - '.github/workflows/scripts/news.sh'
 workflow_dispatch:
  inputs:
   release:
    type:        boolean
    description: 'Release candidate'
    required:    true
    default:     false
   push:
    type:        boolean
    description: 'Push results'
    required:    true
    default:     false
   daily:
    type:        boolean
    description: 'Run daily tasks'
    required:    true
    default:     true
   weekly:
    type:        boolean
    description: 'Run weekly tasks'
    required:    true
    default:     false
   monthly:
    type:        boolean
    description: 'Run monthly tasks'
    required:    true
    default:     false
   minor:
    type:        boolean
    description: 'Force running minor tasks'
    required:    true
    default:     false

defaults:
 run:
  shell: bash

env:
 GHA_SCRIPTS:                 ".github/workflows/scripts"
 MOD_DIR:                     "Fallout2/Fallout1in2"
 GENERATED_DIR:               "Resources/Generated"
 DOTNET_CLI_TELEMETRY_OPTOUT: true

jobs:

 # forked/cloned repositories should use own copy if they want automagic commits
 # feel free to open issue in main repository if you need help/advice tweaking this workflow in your fork
 Maintenance:
  if: github.repository == 'rotators/Fo1in2'
  runs-on: windows-latest
  outputs:       # used by dependant jobs
   event:        ${{ steps.configure.outputs.event }}
   task-any:     ${{ steps.configure.outputs.task-any }}
   task-daily:   ${{ steps.configure.outputs.task-daily }}
   task-weekly:  ${{ steps.configure.outputs.task-weekly }}
   task-monthly: ${{ steps.configure.outputs.task-monthly }}
  steps:

### Activity check
### uses GitHub API to check last non-automagic commit in repository; if it's older than few days (exact value might change from time to time), all other steps are skipped
### weekly/monthly tasks will always run on first day of week/month, even on stale repository

  - name: Configure
    id:   configure
    run:  |
          :
          # old check, requires already cloned repository; left for reference
          # timestamp=$(git log --all --invert-grep --author="<${{ secrets.ANTALASKAYA_EMAIL }}>" --date=unix --format=%ad -1)

          curl -sL https://api.github.com/repos/$GITHUB_REPOSITORY/commits | jq -r '[.[] | select(.author.login != "${{ secrets.ANTALASKAYA_LOGIN }}")][0]' > $HOME/commit.json

          date="$(jq -r '.commit.author.date' $HOME/commit.json)"
          timestamp=$(date --utc -d "$date" +%s)
          author="$(jq -r '.commit.author.name' $HOME/commit.json)"
          url="$(jq -r '.html_url' $HOME/commit.json)"
          days=$(( ( $(date --utc +%s) - $timestamp ) / 86400 ))
          rm -f $HOME/commit.json

          # simplifies checking/displaying which event triggered workflow (especially dispatches)
          event="${{ github.event_name }}"
          if [[ "$event" == "workflow_dispatch" ]]; then
               if [[ "${{ github.event.inputs.push }}" == "true" ]]; then
                  event="${event}:push"
               fi
          fi
          echo GHA_EVENT=$event >> $GITHUB_ENV
          echo "::set-output name=event::$event"
          echo "GitHub event : $event"

          release=0
          daily=0
          weekly="$(date +'%u')"
          weekly_run=1 # monday
          monthly="$(date +'%-d')"
          monthly_run=1 # first day of month
          minor=0
          push=0

          # 'schedule' event
          #  run daily task
          #  push changes
          if [[ "${{ github.event_name }}" == "schedule" ]]; then
             echo "Repository activity : $timestamp $author $url"
             if [[ $days -lt 2 ]]; then
               daily=1
               push=1
             fi
          # 'push' event
          #  run daily tasks
          elif [[ "${{ github.event_name }}" == "push" ]]; then
             daily=1
          # 'workflow_dispatch' event (manual run)
          elif [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
             echo "[WARNING] Ignoring activity limits : workflow triggered manually"

             if [[ "${{ github.even.inputs.release }}" == "true" ]]; then
                echo "Release candidate"
                release=1
             fi

             if [[ "${{ github.event.inputs.push }}" == "true" ]]; then
                push=1
             fi

             if [[ $release -eq 1 ]] || [[ "${{ github.event.inputs.daily }}" == "true" ]]; then
                daily=1
             fi

             if [[ $release -eq 1 ]] || [[ "${{ github.event.inputs.weekly }}" == "true" ]]; then
                weekly=$weekly_run
             fi

             if [[ $release -eq 1 ]] || [[ "${{ github.event.inputs.monthly }}" == "true" ]]; then
                monthly=$monthly_run
             fi

             if [[ $release -eq 1 ]] || [[ "${{ github.event.inputs.minor }}" == "true" ]]; then
                minor=1
             fi
          fi

          if [[ $daily -eq 1 ]]; then
             echo "Running daily tasks"
             echo "GHA_TASK_DAILY=true" >> $GITHUB_ENV
             echo "::set-output name=task-daily::true"
             any=1
          else
             echo "::set-output name=task-daily::false"
          fi

          if [[ $weekly -eq $weekly_run ]]; then
             echo "Running weekly tasks"
             echo GHA_TASK_WEEKLY=true >> $GITHUB_ENV
             echo "::set-output name=task-weekly::true"
             any=1
          else
             echo "::set-output name=task-weekly::false"
          fi

          if [[ $monthly -eq $monthly_run ]]; then
             echo "Running monthly tasks"
             echo "GHA_TASK_MONTHLY=true" >> $GITHUB_ENV
             echo "::set-output name=task-monthly::true"
             any=1
          else
             echo "::set-output name=task-monthly::false"
          fi

          if [[ $any -eq 1 ]]; then
             echo "GHA_TASK_ANY=true" >> $GITHUB_ENV
             echo "::set-output name=task-any::true"
          else
             echo "::set-output name=task-any::false"
          fi

          if [[ $minor -eq 1 ]]; then
             echo "Force running minor tasks"
             echo "GHA_TASK_MINOR=true" >> $GITHUB_ENV
          fi

          if [[ $push -eq 1 ]]; then
             echo "Pushing results"
             echo "GHA_PUSH=true" >> $GITHUB_ENV
          fi

          echo MSBUILD_EXE="$("/c/Program Files (x86)/Microsoft Visual Studio/Installer/vswhere.exe" -latest -requires Microsoft.Component.MSBuild -find MSBuild/**/Bin/MSBuild.exe)" >> $GITHUB_ENV

### Preparations
### clones all interesting repositories used by tasks
### restores/creates cache used by tasks

  - name: Clone sfall-default
    if:   env.GHA_TASK_DAILY == 'true' || env.GHA_TASK_MONTHLY == 'true'
    run:  git clone https://github.com/sfall-team/sfall.git $HOME/sfall-default

  - name: Clone sfall-asm
    if:   env.GHA_TASK_DAILY == 'true'
    run:  git clone --branch=master https://github.com/ghost2238/sfall-asm.git $HOME/sfall-asm

  - name: Clone ScanMsg
    if:   env.GHA_TASK_DAILY == 'true' || env.GHA_TASK_MONTHLY == 'true'
    run:  git clone --branch=master https://github.com/wipe2238/ScanMsg.git $HOME/ScanMsg

  - name: Clone FO1@2
    if:   env.GHA_TASK_ANY == 'true'
    uses: actions/checkout@v4
    with:
     token: ${{ secrets.ANTALASKAYA_TOKEN }}
     fetch-depth: 0

  - name: Preparations
    id:   preparations
    if:   env.GHA_TASK_DAILY == 'true' || env.GHA_TASK_MONTHLY == 'true'
    run:  |
          :
          echo "::group::Get tags"
          git fetch origin +refs/tags/*:refs/tags/*
          echo ::endgroup::

          echo "::group::Get old SHA"
          git --no-pager log --author="<${{ secrets.ANTALASKAYA_EMAIL }}>" > $HOME/git.log
          set +e
          OLD_SCANMSG=$(grep --max-count=1 "\- ScanMsg" $HOME/git.log | awk -F @ '{print $2}' | tr -d ')')
          OLD_ARTIFACTS=$(grep --max-count=1 "\- ModdersPack" $HOME/git.log | awk -F @ '{print $2}' | tr -d ')')
          set -e
          echo "ScanMsg        $OLD_SCANMSG"
          echo "ModdersPack    $OLD_ARTIFACTS"
          rm -f $HOME/git.log
          echo ::endgroup::

          echo "::group::Get new SHA"
          NEW_SCANMSG=$(git -C $HOME/ScanMsg --no-pager log --pretty=format:%H -1 ScanMsg README.md LICENSE.md)
          NEW_ARTIFACTS=$(git -C $HOME/sfall-default --no-pager log --pretty=format:%H -1 artifacts)
          echo "ScanMsg        $NEW_SCANMSG"
          echo "ModdersPack    $NEW_ARTIFACTS"
          echo ::endgroup::

          if [[ "$OLD_SCANMSG" != "$NEW_SCANMSG" ]]; then
             echo "ScanMsg... $OLD_SCANMSG -> $NEW_SCANMSG"
             echo GHA_TASK_SCANMSG=true >> $GITHUB_ENV
          fi

          if [[ "$OLD_ARTIFACTS" != "$NEW_ARTIFACTS" ]]; then
             echo "ModdersPack... $OLD_ARTIFACTS -> $NEW_ARTIFACTS"
             echo GHA_TASK_SFALL_ARTIFACTS=true >> $GITHUB_ENV
          fi

### Major tasks
### always generates commit (if needed)

  # updates .msg files scanner
  - name: ScanMsg update
    if:   env.GHA_TASK_SCANMSG == 'true'
    run:  |
          :
          ok=1
          "$MSBUILD_EXE" $HOME/ScanMsg/ScanMsg.sln -p:Configuration=Release -p:Platform="Any CPU" -target:ScanMsg || ok=0
          if [[ $ok -eq  1 ]] && [[ -f "$HOME/ScanMsg/ScanMsg/Build/Framework/Release/ScanMsg.exe" ]]; then
             cp "$HOME/ScanMsg/ScanMsg/Build/Framework/Release/ScanMsg.exe" Tools/ScanMsg/ScanMsg.exe
             cp "$HOME/ScanMsg/ScanMsg/Build/Framework/Release/ScanMsg.msg" Tools/ScanMsg/ScanMsg.msg
             cp "$HOME/ScanMsg/README.md" Tools/ScanMsg/README.md
             cp "$HOME/ScanMsg/LICENSE.md" Tools/ScanMsg/LICENSE.md
          fi
          SCANMSG_COMMIT=$(git -C $HOME/ScanMsg log --pretty=format:%H -1 ScanMsg README.md LICENSE.md)
          SCANMSG_VERSION=$($GHA_SCRIPTS/ddraw.sh get-dll-version --dll=Tools/ScanMsg/ScanMsg.exe)
          echo "ScanMsg (v${SCANMSG_VERSION}, ${SCANMSG_COMMIT})"
          ls -sh Tools/ScanMsg/ScanMsg.exe

          git diff --quiet || (git add --update && echo "- ScanMsg update (v${SCANMSG_VERSION}, wipe2238/ScanMsg@${SCANMSG_COMMIT})" >> $HOME/gha.commit)

  # updates sfall artifacts
  - name: ModdersPack update
    if:   env.GHA_TASK_SFALL_ARTIFACTS == 'true'
    run:  |
          :
          rm -fR Tools/ModdersPack
          cp -r $HOME/sfall-default/artifacts Tools/ModdersPack

          if [[ -n $(git status --short --untracked-files=all Tools/ModdersPack) ]]; then
             git add Tools/ModdersPack
             SFALL_ARTIFACTS_COMMIT=$(git -C $HOME/sfall-default log --pretty=format:%H -1 artifacts)
             echo "- ModdersPack update (sfall-team/sfall@${SFALL_ARTIFACTS_COMMIT})" >> $HOME/gha.commit
          fi

  # updates scripts sources to Rotators standards
  - name: ReDefine run
    if:   env.GHA_TASK_DAILY == 'true'
    run:  |
          :
          scripts=$(grep "^ScriptsDir" Tools/ReDefine/ReDefine.cfg | awk '{print $3}' | sed -re 's!^[\.\/]+!!')
          headers=$(grep "^HeadersDir" Tools/ReDefine/ReDefine.cfg | awk '{print $3}' | sed -re 's!^[\.\/]+!!')

          Tools/ReDefine/ReDefine.exe --config Tools/ReDefine/ReDefine.cfg --scripts $scripts --headers $headers >/dev/null

          grep "^Changed " ReDefine.log || true
          rm ReDefine*.log
          git diff --quiet || (git add --update && echo "- ReDefine run" >> $HOME/gha.commit)

          echo "MOD_SCRIPTS_DIR=$scripts" >> $GITHUB_ENV
          echo "MOD_HEADERS_DIR=$headers" >> $GITHUB_ENV

  # updates unsafe scripting header
  - name: Voodoo regeneration
    if:   env.GHA_TASK_DAILY == 'true'
    run:  |
          :
          SFASM=$HOME/sfall-asm
          SFASM_EXE=$SFASM/bin/Release/sfall-asm.exe
          HEADER="$MOD_HEADERS_DIR/voodoo.h"

          echo ::group::sfall-asm
          "$MSBUILD_EXE" $SFASM/sfall-asm.sln -p:Configuration=Release 2>&1
          echo ::endgroup::

          $SFASM_EXE $SFASM/patches/fo1in2/ --malloc --update-file=$HEADER -strict

          echo ::group::voodoo.h
          cat $HEADER
          echo ::endgroup::

          unix2dos -q $HEADER
          git diff --quiet || (git add --update && echo "- Voodoo regeneration" >> $HOME/gha.commit)

  # updates scripts sources to be consistent
  - name: Scripts formatting
    if:   env.GHA_TASK_WEEKLY == 'true'
    run:  |
          :
          $GHA_SCRIPTS/format-ssl.sh
          $GHA_SCRIPTS/format-ssl.sh --scripts-dir=$MOD_DIR/mods/

          git diff --quiet || (git add --update && echo "- Scripts formatting" >> $HOME/gha.commit)

  # updates scripts bytecode
  - name: Scripts recompilation
    if:   env.GHA_TASK_DAILY == 'true'
    run:  |
          :
          $GHA_SCRIPTS/compile-ssl.sh --bytecode --optimization=1
          $GHA_SCRIPTS/compile-ssl.sh --scripts-dir=$MOD_DIR/mods/ --bytecode --bytecode-dir=? --optimization=1

          git diff --quiet || (git add --update && echo "- Scripts recompilation" >> $HOME/gha.commit)

  - name: Text formatting
    if:   env.GHA_TASK_WEEKLY == 'true'
    run:  |
          :
          $GHA_SCRIPTS/format-msg.sh

          git diff --quiet || (git add --update && echo "- Text formatting" >> $HOME/gha.commit)

  # updates changes in fo1_base/text/english/ since latest release (read: last added git tag)
  - name: Generate default language changes
    if:   env.GHA_TASK_WEEKLY == 'true'
    run:  |
          :
          rm -fR $GENERATED_DIR/LangChanges
          $GHA_SCRIPTS/diff2dir.sh "$MOD_DIR/mods/fo1_base/text/english/" "$GENERATED_DIR/LangChanges" "$(git describe --tags --abbrev=0)"
          if [[ -d $GENERATED_DIR/LangChanges ]]; then
             find $GENERATED_DIR/LangChanges -type f -exec dos2unix {} \;
          fi

          if [[ -n $(git status --short --untracked-files=all $GENERATED_DIR/LangChanges) ]]; then
             git add $GENERATED_DIR/LangChanges
             echo "- Generate default language changes" >> $HOME/gha.commit
          fi

  # updates list of scripts used on maps
  - name: Generate maps scripts list
    if:   env.GHA_TASK_WEEKLY == 'true'
    run:  |
          cmake -S Tools/MapsScripts/Source/ -B Tools/MapsScripts/Build/
          cmake --build Tools/MapsScripts/Build/ --config Release
          Tools/MapsScripts/Build/Release/MapsScripts.exe --maps $MOD_DIR/mods/fo1_base/maps/ --scripts $MOD_DIR/mods/fo1_base/scripts/ > $GENERATED_DIR/MapsScripts.txt
          git diff --quiet || (git add --update && echo "- Generate maps scripts list" >> $HOME/gha.commit)

### Validation
### checks if any of major tasks wants to generate commit
### prepares commit message header

  - name: Validation
    if:   env.GHA_TASK_ANY == 'true'
    run:  |
          :
          echo ::group::git status
          git status 2>&1
          echo ::endgroup::

          # allow full run; forces minor tasks to run even if major tasks does not generate commit
          if [[ "$GHA_TASK_MINOR" == "true" ]]; then
             echo "# Minor tasks forced to run" >> $HOME/gha.commit
          fi

          if [[ -f "$HOME/gha.commit" ]]; then
             sed -i '1s!^!Progress every day\n!' $HOME/gha.commit
             dos2unix $HOME/gha.commit
             echo "GHA_COMMIT=true" >> $GITHUB_ENV
             cat $HOME/gha.commit
          fi

### Minor tasks
### runs only if at least one of major tasks wants to generate commit, or triggered manually with "full" switch enabled

  # update ddraw.ini comment with sfall version
  # update ddraw.ini setting with mod version
  # synch ddraw.ini with sfall changes
  # update all config files to use dos line endings
  - name: Configuration refresh
    if:   env.GHA_COMMIT == 'true'
    run:  |
          :
          dos2unix $MOD_DIR/ddraw.fo1in2.ini
          gawk -f $GHA_SCRIPTS/ddraw.merge.awk -v override_file=$MOD_DIR/ddraw.fo1in2.ini -v adornments=none Tools/ModdersPack/ddraw.ini > $MOD_DIR/ddraw.ini
          $GHA_SCRIPTS/ddraw.sh set-dll-version --ini=$MOD_DIR/ddraw.ini --dll=$MOD_DIR/ddraw.dll
          $GHA_SCRIPTS/ddraw.sh set --ini=$MOD_DIR/ddraw.ini --cfg=Misc --key=VersionString --val="$($GHA_SCRIPTS/version.sh game --bump)"

          grep "^;v" $MOD_DIR/ddraw.ini
          $GHA_SCRIPTS/ddraw.sh get --ini=$MOD_DIR/ddraw.ini --cfg=Misc --key=VersionString --fmt='"["in_section"]\\n"in_key[1]" = "in_key[2]'

          ### workaround for ddraw.merge hiccup
          # extract PatchFileN settings except PatchFile0 (includes commented values)
          egrep '^;?PatchFile[1-9][0-9]?' $MOD_DIR/ddraw.ini > gha.ddraw.merge.PatchFileN
          # remove PatchFileN settings except PatchFile0 (includes commented values)
          sed -ri '/^;?PatchFile[1-9][0-9]?/d'  $MOD_DIR/ddraw.ini
          # append extracted PatchFileN settings after PatchFile0
          sed -ri '/^PatchFile0=.+$/r gha.ddraw.merge.PatchFileN' $MOD_DIR/ddraw.ini

          ### hint users where translation files really are
          sed -ri 's/sfall\\Translations\.ini/data\\text\\\<language\>\\Translations.ini/g' $MOD_DIR/ddraw.ini

          # cleanup
          sed -ri 'N;/^\n$/D;P;D;' $MOD_DIR/ddraw.ini
          rm -f gha.*

          unix2dos -q $MOD_DIR/*.cfg $MOD_DIR/*.ini $MOD_DIR/config/*.cfg $MOD_DIR/config/*.ini || true
          git diff --quiet || (git add --update && echo "- Configuration refresh" >> $HOME/gha.commit)

  # update news list
  - name: News update
    if:   env.GHA_COMMIT == 'true'
    run:  |
          $GHA_SCRIPTS/news.sh $GITHUB_REPOSITORY NEWS.md [Aa]dded [Cc]hanged [Ff]ixed [Rr]emoved [Tt]weaked
          git diff --quiet || (git add --update && echo "- News update" >> $HOME/gha.commit)

### Push
### generates and displays commit
### pushes generated commit to repository; available only for following events (any other triggers are for testing purposes):
### - schedule
### - workflow_dispatch:push

  - name: Push
    if:   env.GHA_COMMIT == 'true'
    run:  |
          :
          echo ::group::git commit
          dos2unix $HOME/gha.commit
          sed -i '/^#/d' $HOME/gha.commit
          git config --global user.name  "${{ secrets.ANTALASKAYA_NAME }}"
          git config --global user.email "${{ secrets.ANTALASKAYA_EMAIL }}"
          git commit --file="$HOME/gha.commit" 2>&1
          rm -f $HOME/gha.commit
          echo ::endgroup::

          echo ::group::git log
          git log -p -n 1 2>&1
          echo ::endgroup::

          if [[ "$GHA_PUSH" == "true" ]]; then
             echo ::group::git push
             git push 2>&1
             echo ::endgroup::
          else
             echo "[WARNING] Repository not updated : event<$GHA_EVENT> not allowed to modify repository"
          fi
    continue-on-error: true

 Synchronize:
  if: github.repository == 'DISABLED/rotators/Fo1in2'
  needs: Maintenance
  runs-on: windows-latest
  strategy:
   max-parallel: 1
   matrix:
    branch: [ 'fo1_french', 'fo1_german' ]
  steps:

  - name: Preparations
    run:  |
          :
          echo "GHA_EVENT=${{ needs.Maintenance.outputs.event }}" >> $GITHUB_ENV
          echo "GHA_TASK_ANY=${{ needs.Maintenance.outputs.task-any }}" >> $GITHUB_ENV
          echo "GHA_TASK_DAILY=${{ needs.Maintenance.outputs.task-daily }}" >> $GITHUB_ENV
          echo "GHA_TASK_WEEKLY=${{ needs.Maintenance.outputs.task-weekly }}" >> $GITHUB_ENV
          echo "GHA_TASK_MONTHLY=${{ needs.Maintenance.outputs.task-monthly }}" >> $GITHUB_ENV

  - name: Clone FO1@2
    if:   env.GHA_TASK_ANY == 'true'
    uses: actions/checkout@v4
    with:
     token: ${{ secrets.ANTALASKAYA_TOKEN }}
     ref:   ${{ matrix.branch }}

  - name: Fetch master
    run:  git fetch origin master:master

  - name: Synch fo1_base/text/english/
    if:   env.GHA_TASK_DAILY == 'true'
    run:  |
          :
          git checkout master -- $MOD_DIR/mods/fo1_base/text/english/
          git diff --cached --quiet || echo "- Synchronize english .msg files with master branch" >> $HOME/gha.commit

  - name: Validation
    if:   env.GHA_TASK_ANY == 'true'
    run:  |
          :
          echo ::group::git status
          git status 2>&1
          echo ::endgroup::

          if [[ -f "$HOME/gha.commit" ]]; then
             sed -i '1s!^!Progress every day\n!' $HOME/gha.commit
             dos2unix $HOME/gha.commit
             echo GHA_COMMIT=true >> $GITHUB_ENV
             cat $HOME/gha.commit
          fi

  - name: Push
    if:   env.GHA_COMMIT == 'true'
    run:  |
          :
          echo ::group::git commit
          dos2unix $HOME/gha.commit
          sed -i '/^#/d' $HOME/gha.commit
          git config --global user.name  "${{ secrets.ANTALASKAYA_NAME }}"
          git config --global user.email "${{ secrets.ANTALASKAYA_EMAIL }}"
          git commit --file="$HOME/gha.commit" 2>&1
          rm -f $HOME/gha.commit
          echo ::endgroup::

          echo ::group::git log
          git log -p -n 1 2>&1
          echo ::endgroup::

          if [[ "$GHA_EVENT" == "schedule" ]] || [[ "$GHA_EVENT" == "workflow_dispatch:push" ]]; then
             echo ::group::git push
             git push 2>&1
             echo ::endgroup::
          else
             echo "[WARNING] Repository not updated : event<$GHA_EVENT> not allowed to modify repository"
          fi
    continue-on-error: true

